package com.hzit.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hzit.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.SecurityBuilder;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.sql.DataSource;

/**
 * 类名：
 * 作者：WF
 * 功能：
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private MyUserDetailService userDetailService;
	@Autowired
	private DataSource dataSource;
	//1.  配置remember-me的存储器
	@Bean
	public JdbcTokenRepositoryImpl jdbcTokenRepository(){
		JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
		// 配置数据源
		jdbcTokenRepository.setDataSource(dataSource);
		// 配置开始启动时创建表
		jdbcTokenRepository.setCreateTableOnStartup(true);
		return jdbcTokenRepository;
	}
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.exceptionHandling().accessDeniedPage("/user/unauth")
				.and()
				// 0. 配置rember-me功能,它只能记载同一个浏览器中的cookie信息，不能跨浏览器访问
				// tokenRepository: token存储方式
				// tokenValiditySeconds： token有效时间
				// userDetailsService: userDetailService对象
				.rememberMe().tokenRepository(jdbcTokenRepository()).tokenValiditySeconds(7*24*3600).userDetailsService(userDetailService)
				.and()
				.formLogin()
				//1. 指定登录页
				.loginPage("/login.html")
				//2. 指定登录处理页（就是登录表单中action的值，由系统生成）
				.loginProcessingUrl("/login")
				//3. 登录成功后跳转到的页面
				//.successForwardUrl("/user/list")    // 如果用这种方式，因为与/login是一次请求，所以需要用到post请求
				.defaultSuccessUrl("/user/list")
				.and()
				//4. 访问页面的任何请求
				.authorizeRequests()
				//5. 如果是下面指定的路径就放行（permitAll()）
				.antMatchers("/login.html","/webjars/**").permitAll()
				// 授权方法一：使用如下配置的方式实现
				//6.1 授权1：代表有query权限就可以访问/user/findById这个方法
				// .antMatchers("/user/findById").hasAuthority("query")
				//6.2 授权2：代表如要有aaa,bbb,admin三个权限中的某一个在由userDetailService访问访问的数据库中查询出权限串出现，就可以访问资源/user/findById
				// .antMatchers("/user/findById").hasAnyAuthority("aaa","bbb","ccc")
				//6.3 授权3：代表如果有角色ROLE_sale,则可以访问资源/user/findById
				//.antMatchers("/user/findById").hasRole("sale")  // 实际角色名: ROLE_sale
				//6.4 授权4：代表如果有任意角色,则可以访问资源/user/findById
				// .antMatchers("/user/findById").hasAnyRole("sale1","aaa","bbb")
				//7. 任何其它请求都要认证才能访问
				.anyRequest().authenticated()
				//8. 任何请求csrf（跨域请求伪造）都禁用
				.and().csrf().disable();
	}
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 指定验证规则由userDetailService类的loadUserByUsername()方法完成认证
		// 将用户输入的密码使用下面的 passwordEncoder()加密器进行加密后，再进行认证
		auth.userDetailsService(userDetailService).passwordEncoder(passwordEncoder());
	}
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
}
